#include "wav.hpp"

#define LE_STR(a, b, c, d) ((a) + ((b)<<8) + ((c)<<16) + ((d)<<24))

uint32_t readChunkHeader(gvl::octet_stream_reader& reader, uint32_t& size)
{
	uint32_t id = read_uint32_le(reader);
	size = read_uint32_le(reader);

	return id;
}

bool loadWav(gvl::octet_stream_reader& reader, std::vector<int16_t>& data)
{
	try
	{
		uint32_t totalSize;
		if(readChunkHeader(reader, totalSize) != LE_STR('R', 'I', 'F', 'F'))
			return false;

		if(read_uint32_le(reader) != LE_STR('W', 'A', 'V', 'E'))
			return false;

		uint32_t formatTag, channels, samplesPerSec, avgBytesPerSec, blockAlign, bitsPerSample;

		while(!reader.at_eos())
		{
			uint32_t size;
			uint32_t id = readChunkHeader(reader, size);

			switch(id)
			{
				case LE_STR('f', 'm', 't', ' '):
					formatTag = read_uint16_le(reader);
					channels = read_uint16_le(reader);
					samplesPerSec = read_uint32_le(reader);
					avgBytesPerSec = read_uint32_le(reader);
					blockAlign = read_uint16_le(reader);
					bitsPerSample = read_uint16_le(reader);

					if(formatTag != 1)
						return false; // Not PCM
					if(channels != 1)
						return false; // Not mono
					if(samplesPerSec != 44100)
						return false; // Not 44100 Hz
					if(bitsPerSample != 16)
						return false; // Not 16-bit

					reader.try_skip(size - (2+2+4+4+2+2));
					break;

				case LE_STR('d', 'a', 't', 'a'):
					for(uint32_t i = 0; i < size / 2; ++i)
						data.push_back(int16_t(read_uint16_le(reader)));
					return true; // Got data

				default:
					// Skip whole
					reader.try_skip(size);
					break;
			}
		}
	}
	catch(gvl::stream_error& e)
	{
		return false;
	}

	return true;
}

#undef LE_STR
